//
// Created by Tian on 25-5-2.
//
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "driver/pulse_cnt.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "fan_pcnt.h"


static const char *TAG = __FILE__;

static  pcnt_unit_handle_t pcnt_unit = NULL;
// PCNT 配置参数
#define PCNT_INPUT_SIG_IO        (45)               // 脉冲输入GPIO4
#define EXAMPLE_PCNT_HIGH_LIMIT  3000
#define EXAMPLE_PCNT_LOW_LIMIT  (-3000)

#define FAN_PCNT_FILTER_NUM 5

static int pulse_cnt[FAN_PCNT_FILTER_NUM];
static int pulse_read;

int fan_get_rpm_by_pcnt(void)
{
    int pcnt = 0;
    for (int i = 0; i < FAN_PCNT_FILTER_NUM; ++i)
    {
        pcnt += (pulse_cnt[i] * 30);
    }
    return (pcnt / FAN_PCNT_FILTER_NUM);
}

// 定时器回调函数
void pcnt_timer_callback(void* arg)
{
    (void)arg;
    pcnt_unit_get_count(pcnt_unit, &pulse_cnt[pulse_read]);
    if (++pulse_read  == FAN_PCNT_FILTER_NUM)
    {
        pulse_read = 0;
    }
    pcnt_unit_clear_count(pcnt_unit);
}

void fan_pcnt_timer_init(void)
{
    // 创建定时器配置
    const esp_timer_create_args_t timer_args = {
            .callback = &pcnt_timer_callback,  // 设置回调函数
            .arg = NULL,                       // 传递给回调函数的参数
            .name = "pcnt_timer"               // 定时器名称(用于调试)
    };
    esp_timer_handle_t timer_handle;
    // 创建定时器
    ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handle));
    // 启动周期性定时器(1s)
    ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle, 1 * 1000 * 1000)); // 单位是微秒
}

void fan_pcnt_task(const void* arg)
{
    (void)arg;
    ESP_LOGI(TAG, "install pcnt unit");
    const pcnt_unit_config_t unit_config = {
            .high_limit = EXAMPLE_PCNT_HIGH_LIMIT,
            .low_limit = EXAMPLE_PCNT_LOW_LIMIT,
    };

    ESP_ERROR_CHECK(pcnt_new_unit(&unit_config, &pcnt_unit));

    ESP_LOGI(TAG, "set glitch filter");
    const pcnt_glitch_filter_config_t filter_config = {
            .max_glitch_ns = 1000,
    };
    ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_unit, &filter_config));

    ESP_LOGI(TAG, "install pcnt channels");
    const pcnt_chan_config_t chan_a_config = {
            .edge_gpio_num = PCNT_INPUT_SIG_IO,
            .level_gpio_num = -1,
    };
    pcnt_channel_handle_t pcnt_chan_a = NULL;
    ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit, &chan_a_config, &pcnt_chan_a));

    ESP_LOGI(TAG, "set edge and level actions for pcnt channels");
    ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan_a, PCNT_CHANNEL_EDGE_ACTION_HOLD, PCNT_CHANNEL_EDGE_ACTION_INCREASE));

    ESP_LOGI(TAG, "enable pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
    ESP_LOGI(TAG, "clear pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
    ESP_LOGI(TAG, "start pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_start(pcnt_unit));

    fan_pcnt_timer_init();
}

void fan_pcnt_task_init(void)
{
    fan_pcnt_task(NULL);
    //xTaskCreate(fan_pcnt_task, "fan_pcnt_task", 4096, NULL, 10, NULL);
}


